<template>
  <el-card class="editor-container" v-if="editor">
    <template #header>
      <div class="editor-header">
        <template v-for="item in editorMenu">
          <template v-if="['textStyle', 'highlight'].includes(item.type! as string)">
            <el-popover placement="bottom" :width="400" trigger="click">
              <template #reference>
                <div>
                  <el-tooltip effect="dark" :content="item.text" placement="top">
                    <div
                      class="menu-item"
                      :class="{ 'is-active': item.type ? editor.isActive(item.type!) : false }"
                    >
                      <icon-view :name="item.icon"></icon-view>
                    </div>
                  </el-tooltip>
                </div>
              </template>
              <ColorPicker
                :editor="editor"
                :type="(item.type as string)"
                @change="item.click"
              ></ColorPicker>
            </el-popover>
          </template>
          <template v-else-if="['heading','image','table'].includes(item.type! as string)">
            <el-popover placement="bottom" :width="20" trigger="click">
              <template #reference>
                <div>
                  <el-tooltip effect="dark" :content="item.text" placement="top">
                    <div
                      class="menu-item"
                      :class="{ 'is-active': item.type ? editor.isActive(item.type!) : false }"
                    >
                      <icon-view :name="item.icon"></icon-view>
                    </div>
                  </el-tooltip>
                </div>
              </template>
              <HeadingPicker
                :editor="editor"
                @change="item.click"
                v-if="item.type === 'heading'"
              ></HeadingPicker>
              <div v-else class="popover-item">
                <div v-for="child in item.children" @click="child.click">
                  <el-popover
                    v-if="child.text === '插入表格'"
                    placement="right"
                    trigger="hover"
                    popper-class="el-tiptap-popper"
                    ref="popoverRef"
                  >
                    <template #reference>
                      <div>{{ child.text }}</div>
                    </template>
                    <CreateTable @createTable="handleCreateTable"></CreateTable>
                  </el-popover>
                  <div
                    v-else
                    :class="{ 'is-table-active': !isTableActive && item.type === 'table' }"
                  >
                    {{ child.text }}
                  </div>
                </div>
              </div>
            </el-popover>
          </template>

          <template v-else>
            <el-tooltip effect="dark" :content="item.text" placement="top">
              <div
                class="menu-item"
                @click="item.click"
                :class="{ 'is-active': item.type ? editor.isActive(item.type!) : false }"
              >
                <icon-view :name="item.icon"></icon-view>
              </div>
            </el-tooltip>
          </template>
        </template>
      </div>
    </template>
    <div>
      <editor-content :editor="editor" />
    </div>
    <div class="editor-footer" v-if="editorWords">Words: {{ editor.storage.characterCount.characters() }}</div>
  </el-card>
  <el-dialog :title="imageType == 'link' ? '按链接插入图片' : '上传图片'" v-model="imageVisible">
    <el-input v-model="imageUrl" placeholder="请输入图片链接" v-if="imageType == 'link'"></el-input>
    <el-upload
      class="upload-box"
      drag
      action="https://up.eai9.com/"
      multiple
      list-type="picture-card"
      name="uploadfile"
      :show-file-list="false"
      :on-success="uploadSuccess"
      accept=".png, .jpg, .jpeg" 
      v-else
    >
      <el-icon class="el-icon--upload"><upload-filled /></el-icon>
      <div class="el-upload__text">Drop file here or <em>click to upload</em></div>
    </el-upload>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="imageVisible = false">取消</el-button>
        <el-button type="primary" @click="confirmImage"> 确定 </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import { useEditor, EditorContent } from '@tiptap/vue-3'
import { defineProps, defineEmits, computed, ref, unref } from 'vue'
import StarterKit from '@tiptap/starter-kit'
import Underline from '@tiptap/extension-underline'
import Highlight from '@tiptap/extension-highlight'
import Text from '@tiptap/extension-text'
import TextStyle from '@tiptap/extension-text-style'
import { Color } from '@tiptap/extension-color'
import Heading from '@tiptap/extension-heading'
import CharacterCount from '@tiptap/extension-character-count'
import TextAlign from '@tiptap/extension-text-align'
import ListItem from '@tiptap/extension-list-item'
import BulletList from '@tiptap/extension-bullet-list'
import OrderedList from '@tiptap/extension-ordered-list'
import Dropcursor from '@tiptap/extension-dropcursor'
import Image from '@tiptap/extension-image'
import Table from '@tiptap/extension-table'
import TableCell from '@tiptap/extension-table-cell'
import TableHeader from '@tiptap/extension-table-header'
import TableRow from '@tiptap/extension-table-row'
import type { EditorItem } from '@/interface/editor'
import IconView from './components/IconView.vue'
import ColorPicker from './components/ColorPicker.vue'
import HeadingPicker from './components/HeadingPicker.vue'
import CreateTable from './components/CreateTable.vue'
import useTableActive from '@/hooks/useTableActive'
const props = defineProps({
  content: {
    type: String,
    default: ''
  },
  excludeEditorMenu: {
    type: Array,
    default: () => []
  },
  editorMenu: {
    type: Array,
    default: () => []
  },
  editorWords: {
    type: Boolean,
    default: false
  }
})
const emits = defineEmits(['update:content'])
const editor = useEditor({
  extensions: [
    StarterKit,
    Underline.configure({
      HTMLAttributes: {
        class: 'my-custom-class'
      }
    }),
    Highlight.configure({ multicolor: true }),
    Text,
    TextStyle,
    Color,
    Heading.configure({
      levels: [1, 2, 3, 4]
    }),
    CharacterCount,
    TextAlign.configure({
      types: ['heading', 'paragraph']
    }),
    BulletList,
    ListItem,
    OrderedList,
    Dropcursor.configure({
      color: '#d9ecff',
      class: 'dropcursor-class',
      width: 2
    }),
    Image.configure({
      allowBase64: true
    }),
    Table.configure({
      resizable: true
    }),
    TableRow,
    TableHeader,
    TableCell
  ],
  content: props.content,
  onUpdate: ({ editor }) => {
    emits('update:content', editor.getHTML())
  }
})

const imageUrl = ref('')
const imageVisible = ref(false)
const imageType = ref('')
const confirmImage = () => {
  editor?.value?.chain().focus().setImage({ src: imageUrl.value }).run()
  imageVisible.value = false
}
const uploadSuccess = (res: any) => {
  const { data } = res
  editor?.value?.chain().focus().setImage({ src: data }).run()
  imageVisible.value = false
}
const popoverRef = ref()

const handleCreateTable = (table: any) => {
  unref(popoverRef)[0]?.hide()
  const { row, col } = table
  editor?.value?.chain().focus().insertTable({ rows: row, cols: col, withHeaderRow: true }).run()
}
const editorMenu = computed(() => {
  const menu: EditorItem[] = [
    {
      text: '加粗',
      icon: 'bold',
      type: 'bold',
      click: () => {
        editor?.value?.chain().focus().toggleBold().run()
      }
    },
    {
      text: '斜体',
      icon: 'italic',
      type: 'italic',
      click: () => {
        editor?.value?.chain().focus().toggleItalic().run()
      }
    },
    {
      text: '下划线',
      icon: 'underline',
      type: 'underline',
      click: () => {
        editor?.value?.chain().focus().toggleUnderline().run()
      }
    },
    {
      text: '删除线',
      icon: 'strikethrough',
      type: 'strike',
      click: () => {
        editor?.value?.chain().focus().toggleStrike().run()
      }
    },
    {
      text: '标题',
      icon: 'heading',
      type: 'heading',
      click: (item: any) => {
        editor?.value?.chain().focus().toggleHeading({ level: item }).run()
      }
    },
    {
      text: '字体色',
      icon: 'font-color',
      type: 'textStyle',
      click: (item: any) => {
        editor?.value?.chain().focus().setColor(item).run()
      }
    },
    {
      text: '背景色',
      icon: 'highlight',
      type: 'highlight',
      click: (item: any) => {
        editor?.value?.chain().focus().toggleHighlight({ color: item }).run()
      }
    },
    {
      text: '引用',
      icon: 'quote-right',
      type: 'blockquote',
      click: () => {
        editor?.value?.chain().focus().toggleBlockquote().run()
      }
    },
    {
      text: '代码块',
      icon: 'code',
      type: 'codeBlock',
      click: () => {
        editor?.value?.chain().focus().toggleCodeBlock().run()
      }
    },
    {
      text: '图片',
      icon: 'image',
      type: 'image',
      click: () => {},
      children: [
        {
          text: '按链接插入图片',
          click: () => {
            imageVisible.value = true
            imageType.value = 'link'
          }
        },
        {
          text: '上传图片',
          click: () => {
            imageVisible.value = true
            imageType.value = 'upload'
            console.log('上传图片')
          }
        }
      ]
    },
    {
      text: '左对齐',
      icon: 'align-left',
      type: { textAlign: 'left' },
      click: () => {
        editor?.value?.chain().focus().setTextAlign('left').run()
      }
    },
    {
      text: '居中',
      icon: 'align-center',
      type: { textAlign: 'center' },
      click: () => {
        editor?.value?.chain().focus().setTextAlign('center').run()
      }
    },
    {
      text: '右对齐',
      icon: 'align-right',
      type: { textAlign: 'right' },
      click: () => {
        editor?.value?.chain().focus().setTextAlign('right').run()
      }
    },
    {
      text: '两端对齐',
      icon: 'align-justify',
      type: { textAlign: 'justify' },
      click: () => {
        editor?.value?.chain().focus().setTextAlign('justify').run()
      }
    },
    {
      text: '无序列表',
      icon: 'list-ul',
      type: 'bulletList',
      click: () => {
        editor?.value?.chain().focus().toggleBulletList().run()
      }
    },
    {
      text: '有序列表',
      icon: 'list-ol',
      type: 'orderedList',
      click: () => {
        editor?.value?.chain().focus().toggleOrderedList().run()
      }
    },
    {
      text: '水平线',
      icon: 'horizontal-rule',
      type: 'horizontalRule',
      click: () => {
        editor?.value?.chain().focus().setHorizontalRule().run()
      }
    },
    {
      text: '表格',
      icon: 'table',
      type: 'table',
      click: () => {},
      children: [
        {
          text: '插入表格',
          click: () => {}
        },
        {
          text: '头部插入行',
          click: () => {
            editor?.value?.chain().focus().addRowBefore().run()
          }
        },
        {
          text: '尾部插入行',
          click: () => {
            editor?.value?.chain().focus().addRowAfter().run()
          }
        },
        {
          text: '删除行',
          click: () => {
            editor?.value?.chain().focus().deleteRow().run()
          }
        },
        {
          text: '头部插入列',
          click: () => {
            editor?.value?.chain().focus().addColumnBefore().run()
          }
        },
        {
          text: '尾部插入列',
          click: () => {
            editor?.value?.chain().focus().addColumnAfter().run()
          }
        },
        {
          text: '删除列',
          click: () => {
            editor?.value?.chain().focus().deleteColumn().run()
          }
        },
        {
          text: '合并单元格',
          click: () => {
            editor?.value?.chain().focus().mergeCells().run()
          }
        },
        {
          text: '拆分单元格',
          click: () => {
            editor?.value?.chain().focus().splitCell().run()
          }
        },
        {
          text: '删除表格',
          click: () => {
            editor?.value?.chain().focus().deleteTable().run()
          }
        }
      ]
    },
    {
      text: '打印',
      icon: 'print',
      type: 'print',
      click: () => {}
    },
    {
      text: '撤销',
      icon: 'undo',
      type: 'undo',
      click: () => {
        editor?.value?.chain().focus().undo().run()
      }
    },
    {
      text: '重做',
      icon: 'redo',
      type: 'redo',
      click: () => {
        editor?.value?.chain().focus().redo().run()
      }
    }
  ]
  let newMenu = menu
  if (props.excludeEditorMenu.length > 0) {
    newMenu = menu.filter((item: any) => !props.excludeEditorMenu.includes(item.type))
  } else if (props.editorMenu.length > 0) {
    newMenu = menu.filter((item: any) => props.editorMenu.includes(item.type))
  }
  return newMenu
})

const isTableActive = computed(() => {
  if (editor) {
    return useTableActive(editor?.value?.state!)
  }
})
defineExpose({
  editor,
  editorMenu,
  editorMenuIcon: IconView,
  editorColorPicker: ColorPicker,
  editorHeadingPicker: HeadingPicker
})
</script>

<style scoped lang="scss">
.editor-container {
  width: 100%;
  position: relative;
  .editor-header {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    .menu-item {
      width: 40px;
      height: 40px;
      border-radius: 50%;
      transition: all 0.2s ease-in-out;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      &:hover {
        background-color: #f2f3f5;
      }
    }
  }
  .editor-footer {
    position: absolute;
    bottom: 0px;
    width: 100%;
    border-top: 1px solid #e4e7ed;
    left: 0;
    // z-index: 9999;
    background: #ffff;
    height: 40px;
    line-height: 40px;
    text-align: right;
    padding: 0 20px;
    box-sizing: border-box;
    color: #939599;
  }
  .card-header {
    display: flex;
    align-items: center;
    gap: 15px;
  }

  .back-is-active {
    border: 1px solid #fff;
  }

  :deep(.el-card__header) {
    padding: 10px;
  }

  :deep(.el-card__body) {
    padding: 15px;
  }

  :deep(.el-button + .el-button) {
    margin-left: 0;
  }
}
.is-active {
  background-color: #ecf5ff;
  color: #409eff;
}
.popover-item {
  text-align: center;
  div {
    padding: 5px 0;
    cursor: pointer;
    &:hover {
      color: #409eff;
    }
  }
  .is-table-active {
    opacity: 0.2;
    cursor: not-allowed;
  }
}
</style>
<style lang="scss">
.upload-box {
  width: 100%;
  height: 200px;
  .el-upload-list,
  .el-upload,
  .el-upload-dragger {
    width: 100%;
    height: 100%;
  }
}
.ProseMirror:focus {
  outline: 0;
}

.tiptap {
  width: 100%;
  height: 400px;
  padding: 0 15px;
  overflow: auto;
  box-sizing: border-box;
  margin-bottom: 50px;
  /* 定义滚动条宽度 */
  &::-webkit-scrollbar {
    width: 7px;
    border-radius: 50%;
  }

  /* 定义滚动条轨道 */
  &::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 5px;
  }

  /* 定义滚动条滑块 */
  &::-webkit-scrollbar-thumb {
    background: #7fbbff;
    border-radius: 5px;
  }
  P {
    margin: 0;
  }

  ul,
  ol {
    padding: 0 1rem;
  }

  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    line-height: 1.1;
  }

  code {
    background-color: rgba(#616161, 0.1);
    color: #616161;
  }

  pre {
    background: #0d0d0d;
    color: #d9ecff;
    font-family: 'JetBrainsMono', monospace;
    padding: 0.75rem 1rem;
    border-radius: 0.5rem;
    margin: 10px 0;
    code {
      color: inherit;
      padding: 0;
      background: none;
      font-size: 0.8rem;
    }
  }

  img {
    max-width: 100%;
    height: auto;
  }

  blockquote {
    padding-left: 1rem;
    border-left: 4px solid #a4d2ff;
  }

  hr {
    border: none;
    border-top: 2px solid rgba(#0d0d0d, 0.1);
    margin: 1rem 0;
  }
  ol {
    list-style-type: decimal;
  }
  .dropcursor-class {
    margin: 3px 0;
  }
  table {
    border-collapse: collapse;
    table-layout: fixed;
    width: 100%;
    margin: 0;
    overflow: hidden;

    td,
    th {
      min-width: 1em;
      border: 2px solid #ced4da;
      padding: 3px 5px;
      vertical-align: top;
      box-sizing: border-box;
      position: relative;

      > * {
        margin-bottom: 0;
      }
    }

    th {
      font-weight: bold;
      text-align: left;
      background-color: #f1f3f5;
    }

    .selectedCell:after {
      z-index: 2;
      position: absolute;
      content: '';
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
      background: rgba(200, 200, 255, 0.4);
      pointer-events: none;
    }

    .column-resize-handle {
      position: absolute;
      right: -2px;
      top: 0;
      bottom: -2px;
      width: 4px;
      background-color: #adf;
      pointer-events: none;
    }

    p {
      margin: 0;
    }
  }
}

.tableWrapper {
  padding: 1rem 0;
  overflow-x: auto;
}

.resize-cursor {
  cursor: ew-resize;
  cursor: col-resize;
}
.el-tiptap-popper {
  width: auto !important;
  &.el-popper {
    min-width: 0;
  }
}
</style>
